import inspect
import logging

import aiocache
from aiocache import cached_stampede, caches

__all__ = [
    "get_cache",
    "async_cached",
    "init_cache",
]

from fastapi_template.config import app_config


def get_cache(
        cache_name: str = app_config.USE_CACHE_NAME) -> aiocache.RedisCache:
    return caches.get(cache_name)  # type: ignore


def common_key_builder(cache_key: str):

    def key_builder(f, *args, **kwargs):
        function_arg_names = inspect.getfullargspec(f)[0]
        args_dict = dict(zip(function_arg_names, args))
        args_dict.update(kwargs)
        try:
            key = cache_key.format(**args_dict)
        except Exception as e:
            logging.exception("key_builder: cache_key: %s, args_dict: %s",
                              cache_key, args_dict)
            raise e
        return key

    return key_builder


def async_cached(
    key_template: str,
    cache_name: str = app_config.USE_CACHE_NAME,
    ttl=60,
):
    return cached_stampede(
        key_builder=common_key_builder(key_template),
        ttl=ttl,
        alias=cache_name,
        # namespace=app_config.CACHE_NAMESPACE
        # 不要在这里加 namespace . 由于使用了alias, 此处的 namespace 会被忽略.
        # 要加 namespace, 请在 aiocache.caches.set_config 指定.
    )


cache_set_config_called = False


def init_cache():
    global cache_set_config_called
    if cache_set_config_called:
        return

    cache_db = app_config.CACHE_DB

    caches.set_config({
        "default": {
            "cache": "aiocache.SimpleMemoryCache",
            "serializer": {
                "class": "aiocache.serializers.PickleSerializer"
            },
        },
        **({
            "redis": {
                "cache": aiocache.RedisCache,
                "namespace": app_config.CACHE_NAMESPACE,  # 这里加 namespace
                "endpoint": app_config.REDIS_DSN.host,
                "port": app_config.REDIS_DSN.port,
                "db": cache_db,
                "create_connection_timeout": 1,
                "serializer": {
                    "class": "aiocache.serializers.PickleSerializer"
                },
                "plugins": [
                    {
                        "class": "aiocache.plugins.HitMissRatioPlugin"
                    },
                    {
                        "class": "aiocache.plugins.TimingPlugin"
                    },
                ],
            }
        } if not app_config.IS_SAFE_ENV else {}),
    })
    cache_set_config_called = True
    print("cache_set_config_called")


init_cache()
